package com.ecarx.camera.worker.camera.back;

import static com.ecarx.camera.constant.Constants.PHOTO_EXTENSION;
import static com.ecarx.camera.constant.Constants.SIMPLE_DATE_FORMAT;
import static com.ecarx.camera.constant.Constants.VIDEO_EXTENSION;

import android.content.ContentValues;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.PointF;
import android.location.Location;
import android.net.Uri;
import android.provider.MediaStore;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.Observer;

import com.ecarx.camera.constant.Constants;
import com.ecarx.camera.data.ThumbnailData;
import com.ecarx.camera.ui.camera.ICameraUI;
import com.ecarx.camera.utils.LogUtils;
import com.ecarx.camera.utils.StorageUtils;
import com.ecarx.camera.utils.Utils;
import com.ecarx.camera.worker.camera.CameraListener;
import com.ecarx.camera.worker.camera.ICameraViewWorker;
import com.ecarx.camera.worker.camera.timer.RecordingTimerHelper;
import com.ecarx.camera.worker.config.ConfigManager;
import com.ecarx.camera.worker.config.OnVideoMutedChangedListener;
import com.ecarx.camera.worker.event.RecordingTimerEvent;
import com.jeremyliao.liveeventbus.LiveEventBus;
import com.otaliastudios.cameraview.CameraView;
import com.otaliastudios.cameraview.PictureResult;
import com.otaliastudios.cameraview.VideoResult;
import com.otaliastudios.cameraview.controls.Audio;
import com.otaliastudios.cameraview.controls.Facing;
import com.otaliastudios.cameraview.internal.ExifHelper;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.OutputStream;

public class BackCameraViewWorker implements ICameraViewWorker, OnVideoMutedChangedListener {
    private static final String TAG = "BackCameraViewWorker";

    private ICameraUI mCameraUI;
    private CameraView mCameraView;

    private final RecordingTimerHelper mRecordingTimerHelper = new RecordingTimerHelper(Constants.FacingType.EXTERIOR);
    private final Observer<RecordingTimerEvent> mRecordingTimerEventObserver = new Observer<RecordingTimerEvent>() {
        @Override
        public void onChanged(RecordingTimerEvent recordingTimerEvent) {
            if (Constants.FacingType.EXTERIOR == recordingTimerEvent.facingType) {
                if (mCameraUI != null) {
                    mCameraUI.setVideoRecordingTimeText(recordingTimerEvent.hours, recordingTimerEvent.minutes, recordingTimerEvent.seconds);
                }
            }
        }
    };

    private final CameraListener mCameraListener = new CameraListener() {
        @Override
        public void onZoomChanged(float newValue, @NonNull float[] bounds, @Nullable PointF[] fingers) {
        }

        @Override
        public void onPictureTaken(@NonNull PictureResult result) {
            if (result == null || result.getFacing() != Facing.BACK) {
                return;
            }
            LogUtils.d(TAG, "onPictureTaken result_length:" + (result == null ? "null" : (result.getData() == null ? 0 : result.getData().length)));
            String fileName = "PIC_" + SIMPLE_DATE_FORMAT.format(System.currentTimeMillis()) + PHOTO_EXTENSION;
            ContentValues contentValues = new ContentValues();
            contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, Constants.RELATIVE_PATH);
            contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
            Uri uriInsert = Utils.getApp().getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
            try {
                OutputStream os = Utils.getApp().getContentResolver().openOutputStream(uriInsert);
                BufferedOutputStream bos = new BufferedOutputStream(os);
                bos.write(result.getData());
                bos.close();
            } catch (Throwable throwable) {
                LogUtils.w(TAG, "onPictureTaken writeFile " + fileName, throwable);
            }

            if(result.getLocation()!=null){
                ExifHelper.setExifLocation(uriInsert, result.getLocation().getLatitude(), result.getLocation().getLongitude());
            }

            if (mCameraUI != null) {
                mCameraUI.updateOnPictureTaken(true);
            }
        }

        @Override
        public void onVideoRecordingStart() {
            if (mCameraView == null || mCameraView.getFacing() != Facing.BACK) {
                return;
            }
            LogUtils.d(TAG, "onVideoRecordingStart");
            mRecordingTimerHelper.start();
            if (mCameraUI != null) {
                mCameraUI.updateOnVideoRecordingStarted();
            }
        }

        @Override
        public void onVideoTaken(@NonNull VideoResult result) {
            if (result == null || result.getFacing() != Facing.BACK) {
                return;
            }
            LogUtils.d(TAG, "onVideoTaken, result = [" + (result == null ? null : result.getFile()) + "]");
            if (mCameraUI != null) {
                mCameraUI.updateOnVideoTaken(true);
            }
        }
    };

    @Override
    public void init() {
    }

    @Override
    public void bindUI(ICameraUI cameraUI) {
        mCameraUI = cameraUI;
        if (cameraUI != null) {
            LiveEventBus.get(RecordingTimerEvent.class).observe(cameraUI.getFragment(), mRecordingTimerEventObserver);
        }
    }

    @Override
    public void doOnResume() {
        onExteriorVideoMutedChanged(ConfigManager.getInstance().isExteriorVideoMuted());
        ConfigManager.getInstance().addOnVideoMutedChangedListener(this);

        if (mCameraUI != null) {
            mCameraUI.showVideoRecordingIndicator(false);
            mCameraUI.setVideoMutedChecked(ConfigManager.getInstance().isExteriorVideoMuted());
        }
        mRecordingTimerHelper.stop();
    }

    @Override
    public void doOnPause() {
        ConfigManager.getInstance().removeOnVideoMutedChangedListener(this);

        if (mCameraView != null) {
            if (mCameraView.isTakingVideo()) {
                LogUtils.d(TAG, "doOnPause, stopVideo when isTakingVideo");
                mCameraView.stopVideo();
            }
            if (mCameraUI != null) {
                mCameraUI.updateVideoRecordingButton(mCameraView.isTakingVideo());
            }
        }
    }

    @Override
    public void doOnDestroy() {
        if (mCameraView != null) {
            mCameraView.removeCameraListener(mCameraListener);
        }
    }

    @Override
    public void setCameraLocation(Location location) {
    }

    @Override
    public void setCameraZoom(float zoomRatio) {
    }

    @Override
    public void setVideoMode(boolean isVideoMode) {
    }

    @Override
    public void setUsePhotoTimerCountdown(boolean usePhotoTimerCountdown) {
    }

    @Override
    public void setUseVideoTimelapseMode(boolean useVideoTimelapseMode) {
    }

    @Override
    public boolean setCameraAudioMuted(boolean isMuted) {
        return ConfigManager.getInstance().setExteriorVideoMuted(isMuted);
    }

    @Override
    public void doCapture() {
        if (checkStorage()) {
            return;
        }
        doCaptureInner();
    }

    private void doCaptureInner() {
        if (mCameraUI != null) {
            mCameraUI.updateOnPhotoTakingStarted();
        }
        if (mCameraView != null) {
            mCameraView.takePictureSnapshot();
        }
    }

    @Override
    public void startRecordVideo() {
        if (checkStorage()) {
            mCameraUI.updateOnVideoTaken(false);
            return;
        }
        recordVideoInner();
    }

    private void recordVideoInner() {
        String fileName = "VID_" + SIMPLE_DATE_FORMAT.format(System.currentTimeMillis()) + VIDEO_EXTENSION;
        ContentValues contentValues = new ContentValues();
        contentValues.put(MediaStore.Video.Media.RELATIVE_PATH, Constants.RELATIVE_PATH);
        contentValues.put(MediaStore.Video.Media.DISPLAY_NAME, fileName);
        Uri uriInsert = Utils.getApp().getContentResolver().insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, contentValues);
        try {
            OutputStream os = Utils.getApp().getContentResolver().openOutputStream(uriInsert);
            BufferedOutputStream bos = new BufferedOutputStream(os);
            // bos.write();
            bos.close();
        } catch (Throwable throwable) {
            LogUtils.w(TAG, "recordVideoInner createFile " + fileName, throwable);
        }

        Cursor query = Utils.getApp().getContentResolver().query(uriInsert, null, null, null, null);
        if (query != null) {
            if (query.moveToFirst()) {
                int columnIndexOfAbsolutePath = query.getColumnIndex(MediaStore.Video.VideoColumns.DATA);
                if (columnIndexOfAbsolutePath > 0) {
                    String absolutePath = query.getString(columnIndexOfAbsolutePath);
                    if (mCameraView != null) {
                        mCameraView.takeVideoSnapshot(new File(absolutePath));
                    }
                }
            }
            query.close();
        }
    }

    @Override
    public void stopRecordVideo() {
        if (mCameraView != null && mCameraView.isTakingVideo()) {
            mCameraView.stopVideo();
            // 点击停止录像时停止计时
            LogUtils.d(TAG, "stopRecordVideo, stop timer.");
            mRecordingTimerHelper.stop();
        }
    }

    @Override
    public ThumbnailData getLatestThumbnail() {
        ThumbnailData thumbnailData = new ThumbnailData().setFacingType(Constants.FacingType.EXTERIOR);
        Uri queryUri = MediaStore.Files.getContentUri("external");
        String selection = MediaStore.MediaColumns.RELATIVE_PATH + " = ?";
        String[] selectionArgs = new String[]{Constants.RELATIVE_PATH};
        Cursor query = Utils.getApp().getContentResolver().query(queryUri, null, selection, selectionArgs, null);
        if (query != null) {
            if (query.moveToLast()) {
                do {
                    int columnIndexOfOwnerPackageName = query.getColumnIndex(MediaStore.MediaColumns.OWNER_PACKAGE_NAME);
                    if (columnIndexOfOwnerPackageName <= 0) {
                        continue;
                    }
                    String ownerPackageName = query.getString(columnIndexOfOwnerPackageName);
                    if (!Utils.getApp().getPackageName().equals(ownerPackageName)) {
                        continue;
                    }
                    int columnIndexOfId = query.getColumnIndex(MediaStore.Files.FileColumns._ID);
                    int columnIndexOfMediaType = query.getColumnIndex(MediaStore.Files.FileColumns.MEDIA_TYPE);
                    Bitmap bitmap = null;
                    if (columnIndexOfId > 0 && columnIndexOfMediaType > 0) {
                        int id = query.getInt(columnIndexOfId);
                        int mediaType = query.getInt(columnIndexOfMediaType);
                        if (mediaType == MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE) {
                            bitmap = MediaStore.Images.Thumbnails.getThumbnail(Utils.getApp().getContentResolver(), id, MediaStore.Images.Thumbnails.MINI_KIND, null);
                            thumbnailData.setVideo(false);
                        } else if (mediaType == MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO) {
                            bitmap = MediaStore.Video.Thumbnails.getThumbnail(Utils.getApp().getContentResolver(), id, MediaStore.Video.Thumbnails.MINI_KIND, null);
                            thumbnailData.setVideo(true);
                        }
                    }
                    if (bitmap != null) {
                        thumbnailData.setBitmap(bitmap);
                        break;
                    }
                } while (query.moveToPrevious());
            }
            query.close();
        }
        return thumbnailData;
    }

    @Override
    public void onInteriorVideoMutedChanged(boolean videoMuted) {
    }

    @Override
    public void onExteriorVideoMutedChanged(boolean videoMuted) {
        if (mCameraView != null) {
            mCameraView.setAudio(videoMuted ? Audio.OFF : Audio.ON);
        }
    }

    @Override
    public void setCameraView(CameraView cameraView) {
        mCameraView = cameraView;
        if (mCameraView != null) {
            mCameraView.addCameraListener(mCameraListener);
        }
    }

    /**
     * 检测磁盘空间
     * @return
     */
    private boolean checkStorage() {
        return mCameraUI != null && mCameraUI.getFragment() != null && StorageUtils.checkStorage(mCameraUI.getFragment().getChildFragmentManager());
    }
}
